home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / GVECTORS.ZIP / GVECTORS.CPP < prev    next >
C/C++ Source or Header  |  1995-05-28  |  22KB  |  759 lines

  1. //            ┌────────────────────────────────────────┐
  2. //            │            Gouraud Vectors             │
  3. //            │  coded by Tumblin / Bodies In Motion   │
  4. //            │            (Terry Sznober)             │
  5. //            │ Copyright (c) 1995 by Bodies In Motion │
  6. //            └────────────────────────────────────────┘
  7. //────────────────────────────────────────────────────────────────────────
  8.  
  9. // Last modified May 28, 1995
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <math.h>
  14. #include <conio.h>
  15. #include <dos.h>
  16. #include <process.h>
  17. #include <xlib_all.h>
  18.  
  19. #include "gvectors.h"
  20.  
  21. //──────────────────────── fixed point math code ─────────────────────────
  22.  
  23. typedef long Fixedpoint;
  24.  
  25. #define Int2Fixed(a)  (Fixedpoint)((Fixedpoint)(a) << 16)
  26. #define Fixed2Int(a)  (int)((a) >> 16)
  27. #define Float2Fixed(a)  ((Fixedpoint)((a) * 65536.0))
  28. #define Fixed2Float(a)  ((a) / 65536.0)
  29.  
  30. extern "C" {
  31.                          Fixedpoint FixedMul(Fixedpoint,Fixedpoint);
  32.                          Fixedpoint FixedDiv(Fixedpoint,Fixedpoint);
  33.                      };
  34.  
  35.  
  36. //--------------------------------------------------------------------------
  37.  
  38. // maximum # of degrees for sin and cos tables
  39. #define MAXDEGREES 720
  40.  
  41. // distance from users eye to screen surface in pixels
  42. #define EYE_DISTANCE Int2Fixed(256)
  43.  
  44. //──────────────────────────── data structures ───────────────────────────
  45.  
  46. char filename[80]; // filename of object to load/save
  47.  
  48. Fixedpoint cosine[MAXDEGREES];  // cosine lookup table
  49. Fixedpoint sine[MAXDEGREES];    // sine lookup table
  50.  
  51. // these are for the gouraud shading routines
  52. int edge_l[240];
  53. int edge_r[240];
  54. char color_l[240];
  55. char color_r[240];
  56.  
  57. #define MAXVERTICES 300
  58. #define MAXPOLYGONS 300
  59. #define MAXPOLYVERT 20
  60.  
  61. // structure of one vertex
  62. typedef struct
  63. {
  64.     Fixedpoint Vox,Voy,Voz; // vertex original coordinates
  65.     Fixedpoint Vwx,Vwy,Vwz; // vertex working  coordinates
  66.     int Vsx,Vsy,Vsz; // vertex screen coordinates
  67.     Fixedpoint Nox,Noy,Noz; // normal's original coordinates
  68.     Fixedpoint Nwx,Nwy,Nwz; // normal's working coordinates
  69.     int shadedcolor; // color of vertex used for gouraud shading
  70. } VertexTYPE;
  71.  
  72. // structure of one polygon
  73. typedef struct
  74. {
  75.     int NumOfVertices; // number of vertices that make up the polygon
  76.     int Vertex[MAXPOLYVERT]; // vertex indices in counter clockwise order
  77.     int zcenter; // center z coordinate (used for polygon sorting)
  78.     int color; // color group of polygon (before shading)
  79.     int shadedcolor; // actual color value of polygon after shading
  80. } PolygonTYPE;
  81.  
  82. // object structure
  83. typedef struct
  84. {
  85.     Fixedpoint Ox,Oy,Oz; // coordinates of object's origin
  86.     int Ax,Ay,Az; // object's rotation angles
  87.     int NumOfVertices; // number of vertices in object
  88.     VertexTYPE Vertex[MAXVERTICES]; // all vertices in object
  89.     int NumOfPolygons; // number of polygons in object
  90.     PolygonTYPE Polygon[MAXPOLYGONS]; // all polygons in object
  91. } ObjectTYPE;
  92.  
  93. ObjectTYPE Object; // one object
  94.  
  95. int NumOfSortedPolygons; // number of sorted visible polygons
  96. int PolygonOrderList[MAXPOLYGONS]; // list of polygon indices for qsorting
  97.  
  98. // structure of light source
  99. typedef struct
  100. {
  101.     Fixedpoint x,y,z; // coodinates of light source
  102.     Fixedpoint wx,wy,wz; // working (intermediate) coordinates
  103.     int ax,ay,az; // rotation angles
  104. } LightSourceTYPE;
  105.  
  106. LightSourceTYPE LightSource; // one light source
  107.  
  108.  
  109. int eboxtop1; // erase box top coordinate (current frame)
  110. int eboxbottom1; // erase box bottom coordinate (current frame)
  111. int eboxleft1; // erase box left coordinate (current frame)
  112. int eboxright1; // erase box right coordinate (current frame)
  113. int eboxtop2; // erase box top coordinate (one frame ago)
  114. int eboxbottom2; // erase box bottom coordinate (one frame ago)
  115. int eboxleft2; // erase box left coordinate (one frame ago)
  116. int eboxright2; // erase box right coordinate (one frame ago)
  117. int eboxtop3; // erase box top coordinate (two frames ago)
  118. int eboxbottom3; // erase box bottom coordinate (two frames ago)
  119. int eboxleft3; // erase box left coordinate (two frames ago)
  120. int eboxright3; // erase box right coordinate (two frames ago)
  121.  
  122. // dot product, used for light source shading
  123. Fixedpoint DotProduct;
  124.  
  125.  
  126. //──────────────────────── function prototypes ───────────────────────────
  127.  
  128. int main(void);
  129. void CreateLookupTables(void);
  130. void RotateObject(void);
  131. void LoadObject(void);
  132. void SortPolygons(void);
  133. int ComparePolygons(const void *a, const void *b);
  134. void DrawPolygons(void);
  135. void CalculateColor(void);
  136. void SetupLightSource(void);
  137. void RotateNormals(void);
  138. void RotateLightSource(void);
  139. void CalculateNormals(void);
  140. void GTriangle(float,float,float, float,float,float, float,float,float,int);
  141. void ScanEdge(float,float,float,float,float,float);
  142.  
  143.  
  144. //──────────────── code to create sin and cos lookup tables ──────────────
  145.  
  146. void CreateLookupTables(void)
  147. {
  148.     int i;
  149.     for(i=0; i<MAXDEGREES; i++)
  150.     {
  151.         cosine[i]=Float2Fixed(cos((float)i*360/MAXDEGREES * 3.14159265 / 180.0));
  152.         sine[i]  =Float2Fixed(sin((float)i*360/MAXDEGREES * 3.14159265 / 180.0));
  153.     }
  154. }
  155.  
  156.  
  157. //─────────────────────────────── rotate object ───────────────────────
  158.  
  159.  
  160. void RotateObject(void)
  161. {
  162.     int i;
  163.     Fixedpoint nx,ny,nz,cosxangle,sinxangle,cosyangle,sinyangle,coszangle,sinzangle;
  164.  
  165.     VertexTYPE *vert; // pointer to a vertex structure
  166.  
  167.     // get the sine and cosine angles to save time from table lookup
  168.     sinxangle=sine[Object.Ax];
  169.     cosxangle=cosine[Object.Ax];
  170.     sinyangle=sine[Object.Ay];
  171.     cosyangle=cosine[Object.Ay];
  172.     sinzangle=sine[Object.Az];
  173.     coszangle=cosine[Object.Az];
  174.  
  175.     // initialize the erase-box info to the extreme values
  176.     eboxtop1=240;
  177.     eboxleft1=320;
  178.     eboxright1=0;
  179.     eboxbottom1=0;
  180.  
  181.     // loop through all vertices in object
  182.     for(i=0;i<Object.NumOfVertices;i++)
  183.     {
  184.         vert=&Object.Vertex[i];
  185.  
  186.         // rotate around the x-axis
  187.         vert->Vwz=FixedMul(vert->Voy,cosxangle) - FixedMul(vert->Voz,sinxangle);
  188.         vert->Vwy=FixedMul(vert->Voy,sinxangle) + FixedMul(vert->Voz,cosxangle);
  189.         vert->Vwx=vert->Vox;
  190.  
  191.         // rotate around the y-axis
  192.         nx=FixedMul(vert->Vwx,cosyangle) - FixedMul(vert->Vwz,sinyangle);
  193.         nz=FixedMul(vert->Vwx,sinyangle) + FixedMul(vert->Vwz,cosyangle);
  194.         vert->Vwx=nx;
  195.         vert->Vwz=nz;
  196.  
  197.         // rotate around the z-axis
  198.         nx=FixedMul(vert->Vwx,coszangle) - FixedMul(vert->Vwy,sinzangle);
  199.         ny=FixedMul(vert->Vwx,sinzangle) + FixedMul(vert->Vwy,coszangle);
  200.         vert->Vwx=nx;
  201.         vert->Vwy=ny;
  202.  
  203.         // project the 3-D coordinates to screen coordinates
  204.         vert->Vsx=Fixed2Int(FixedMul(FixedDiv(vert->Vwx+Object.Ox,vert->Vwz+Object.Oz),EYE_DISTANCE)) + 160;
  205.         vert->Vsy=Fixed2Int(FixedMul(FixedDiv(vert->Vwy+Object.Oy,vert->Vwz+Object.Oz),EYE_DISTANCE)) + 120;
  206.         vert->Vsz=Fixed2Int(vert->Vwz+Object.Oz);
  207.  
  208.         // while we are at it, update the erase-box information
  209.         if(vert->Vsx < eboxleft1) eboxleft1 = vert->Vsx;
  210.         if(vert->Vsx > eboxright1) eboxright1 = vert->Vsx;
  211.         if(vert->Vsy < eboxtop1) eboxtop1 = vert->Vsy;
  212.         if(vert->Vsy > eboxbottom1) eboxbottom1 = vert->Vsy;
  213.     }
  214.  
  215.     // clip the erase box
  216.     if(eboxleft1<0) eboxleft1=0;
  217.     if(eboxtop1<0) eboxtop1=0;
  218.     if(eboxright1>319) eboxright1=319;
  219.     if(eboxbottom1>239) eboxbottom1=239;
  220. }
  221.  
  222.  
  223. //─────────────────────── load object─────────────────────────────────────
  224.  
  225.  
  226. void LoadObject(void)
  227. {
  228.     FILE *file;
  229.     char filename[80];
  230.     int i,j,temp,result;
  231.  
  232.     VertexTYPE *vert; // pointer to a vertex structure
  233.  
  234.     printf("LOAD OBJECT\n===========\n\n");
  235.  
  236.     // show the current directory's .V10 files
  237.     result = system("dir *.v10 /w/p");
  238.     if (result)
  239.     {
  240.         printf("\nSorry but couldn't list the V10 files of the current directory\n");
  241.     }
  242.  
  243.     // get the filename from user
  244.     printf("\n\nEnter filename (filename.V10) : ");
  245.     gets(filename);
  246.  
  247.     // open the file to write to it
  248.     if ((file = fopen(filename,"rb")) == NULL)
  249.     {
  250.         printf("\n\nCannot open input file.\n");
  251.     }
  252.     else
  253.     {
  254.         // okay file is ready to read data from it
  255.  
  256.         // read number of dots in file
  257.         fread(&Object.NumOfVertices,sizeof(int),1,file);
  258.  
  259.         // read in all of the object's vertices
  260.         for(i=0;i < Object.NumOfVertices; i++)
  261.         {
  262.             fread(&temp,sizeof(int),1,file);
  263.             Object.Vertex[i].Vox=Int2Fixed(temp);
  264.             fread(&temp,sizeof(int),1,file);
  265.             Object.Vertex[i].Voy=Int2Fixed(temp);
  266.             fread(&temp,sizeof(int),1,file);
  267.             Object.Vertex[i].Voz=Int2Fixed(temp);
  268.         }
  269.  
  270.         // read in the number of polygons
  271.         fread(&Object.NumOfPolygons,sizeof(int),1,file);
  272.         // read in the information for each polygon
  273.         for(i=0; i < Object.NumOfPolygons; i++)
  274.         {
  275.             // read in the number of vertices in polygon
  276.             fread(&Object.Polygon[i].NumOfVertices,sizeof(int),1,file);
  277.             // read in the polygon's vertices (already in counter clockwise order)
  278.             for(j=0; j< Object.Polygon[i].NumOfVertices; j++)
  279.             {
  280.                 fread(&Object.Polygon[i].Vertex[j],sizeof(int),1,file);
  281.             }
  282.             // read the color of the polygon
  283.             fread(&Object.Polygon[i].color,sizeof(int),1,file);
  284.         }
  285.  
  286.         // we're finished, close the file
  287.         fclose(file);
  288.         printf("\n\nObject loaded.\n");
  289.     }
  290. }
  291.  
  292.  
  293. //────────────────────────── make visible polygon list ─────────────────────
  294.  
  295. void MakePolygonList(void)
  296. {
  297.     int i,j,k;
  298.  
  299.     VertexTYPE *v0,*v1,*v2;
  300.  
  301.     j=0;
  302.     for(i=0;i<Object.NumOfPolygons;i++)
  303.     {
  304.         v0=&Object.Vertex[Object.Polygon[i].Vertex[0]];
  305.         v1=&Object.Vertex[Object.Polygon[i].Vertex[1]];
  306.         v2=&Object.Vertex[Object.Polygon[i].Vertex[2]];
  307.  
  308.         // if expression results in a negative then polygon is visible
  309.         if( ((v1->Vsx - v0->Vsx) * (v2->Vsy - v0->Vsy) - (v1->Vsy - v0->Vsy) * (v2->Vsx - v0->Vsx)) < 0 )
  310.         {
  311.             PolygonOrderList[j++]=i;
  312.         }
  313.     }
  314.     NumOfSortedPolygons=j;
  315. }
  316.  
  317. //──────────────────────────────────── sort polygons ───────────────────────
  318.  
  319.  
  320. void SortPolygons(void)
  321. {
  322.     int i,j;
  323.     int maxz,minz;
  324.     int temp;
  325.     PolygonTYPE *poly;
  326.  
  327.     // first find the distance of each polygon (from midpoint of max & min z's)
  328.     for(i=0;i<Object.NumOfPolygons;i++)
  329.     {
  330.  
  331.         poly=&Object.Polygon[i];
  332.         minz=65535; // set to extreme values
  333.         maxz=-65536; // set to extreme values
  334.         for(j=0;j<poly->NumOfVertices;j++)
  335.         {
  336.             if(Object.Vertex[poly->Vertex[j]].Vsz < minz)
  337.             {
  338.                 minz=Object.Vertex[poly->Vertex[j]].Vsz;
  339.             }
  340.             if(Object.Vertex[poly->Vertex[j]].Vsz > maxz)
  341.             {
  342.                 maxz=Object.Vertex[poly->Vertex[j]].Vsz;
  343.             }
  344.         }
  345.         // now calculate the distance
  346.         poly->zcenter=(maxz+minz)>>1;
  347.     }
  348.  
  349.     // qsort the polygons
  350.     qsort((const void *)PolygonOrderList,NumOfSortedPolygons,sizeof(PolygonOrderList[0]),ComparePolygons);
  351. }
  352.  
  353. //────────────────────────── compare zcenter (for qsort) ───────────────────
  354.  
  355. int ComparePolygons(const void *a, const void *b)
  356. {
  357.     if( Object.Polygon[*(int *)a].zcenter < Object.Polygon[*(int *)b].zcenter )
  358.     {
  359.         return -1;
  360.     }
  361.     else if( Object.Polygon[*(int *)a].zcenter > Object.Polygon[*(int *)b].zcenter )
  362.     {
  363.         return +1;
  364.     }
  365.     else
  366.     {
  367.         return 0;
  368.     }
  369. }
  370.  
  371. //──────────────────────────────────── draw polygons ───────────────────────
  372.  
  373.  
  374. void DrawPolygons(void)
  375. {
  376.     int i,j;
  377.  
  378.     x_rect_fill(eboxleft3,eboxtop3,eboxright3+1,eboxbottom3+1,HiddenPageOffs,0);
  379.  
  380.     for(i=0;i<NumOfSortedPolygons;i++)
  381.     {
  382.         // loop through all vertices in polygon and draw triangular pieces
  383.         for(j=0; j < Object.Polygon[PolygonOrderList[i]].NumOfVertices-2;j++)
  384.         {
  385.             GTriangle((float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[0]].Vsx,
  386.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[0]].Vsy,
  387.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[0]].shadedcolor,
  388.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[j+1]].Vsx,
  389.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[j+1]].Vsy,
  390.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[j+1]].shadedcolor,
  391.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[j+2]].Vsx,
  392.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[j+2]].Vsy,
  393.                                 (float)Object.Vertex[Object.Polygon[PolygonOrderList[i]].Vertex[j+2]].shadedcolor,
  394.                                 HiddenPageOffs);
  395.         }
  396.     }
  397.  
  398.     // update the older erase box information
  399.     eboxtop3 = eboxtop2; eboxtop2 = eboxtop1;
  400.     eboxleft3 = eboxleft2; eboxleft2 = eboxleft1;
  401.     eboxright3 = eboxright2; eboxright2 = eboxright1;
  402.     eboxbottom3 = eboxbottom2; eboxbottom2 = eboxbottom1;
  403.  
  404. }
  405.  
  406.  
  407. //──────────────────────────── calculate normals ─────────────────────────
  408.  
  409.  
  410. void CalculateNormals(void)
  411. {
  412.     double xlen,ylen,zlen,length;
  413.  
  414.     //This will calculate the normals of the vertices for gouraud shading
  415.  
  416.     for(int i=0;i < Object.NumOfVertices; i++)
  417.     {
  418.  
  419.         // calculate perpendicular via the vertex and the vertex*2
  420.         // ie. we are scaling the vertices and use them as the new vertices
  421.         // for gouraud shading.  This is not quite correct though, because
  422.         // you wouldn't be accounting for polygons that face the object's
  423.         // center.
  424.         xlen = Fixed2Float(FixedMul(Object.Vertex[i].Vox,Int2Fixed(2)));
  425.         ylen = Fixed2Float(FixedMul(Object.Vertex[i].Voy,Int2Fixed(2)));
  426.         zlen = Fixed2Float(FixedMul(Object.Vertex[i].Voz,Int2Fixed(2)));
  427.  
  428.         // calculate the length of the normal
  429.         length = sqrt(xlen*xlen + ylen*ylen + zlen*zlen);
  430.  
  431.         // scale it to a unit normal
  432.         Object.Vertex[i].Nox = Float2Fixed(xlen / length);
  433.         Object.Vertex[i].Noy = Float2Fixed(ylen / length);
  434.         Object.Vertex[i].Noz = Float2Fixed(zlen / length);
  435.     }
  436. }
  437.  
  438.  
  439. //──────────────────────────── calculate color ───────────────────────────
  440.  
  441. void CalculateColor(void)
  442. {
  443.     int i;
  444.     int color;
  445.  
  446.     for(i=0; i < Object.NumOfVertices; i++)
  447.     {
  448.         DotProduct=FixedMul(Object.Vertex[i].Nwx , LightSource.wx) +
  449.                              FixedMul(Object.Vertex[i].Nwy , LightSource.wy) +
  450.                              FixedMul(Object.Vertex[i].Nwz , LightSource.wz);
  451.  
  452.         Object.Vertex[i].shadedcolor = 56 + Fixed2Int(FixedMul(DotProduct,Int2Fixed(40)));
  453.     }
  454. }
  455.  
  456.  
  457. //──────────────────────────── rotate normals ─────────────────────────────
  458.  
  459.  
  460. void RotateNormals(void)
  461. {
  462.     int i;
  463.     Fixedpoint nx,ny,nz,cosxangle,sinxangle,cosyangle,sinyangle,coszangle,sinzangle;
  464.     VertexTYPE *vert; // pointer to a vertex structure
  465.  
  466.     // get sine and cosine angles to save time from table lookup in inner loop
  467.     sinxangle=sine[Object.Ax];
  468.     cosxangle=cosine[Object.Ax];
  469.     sinyangle=sine[Object.Ay];
  470.     cosyangle=cosine[Object.Ay];
  471.     sinzangle=sine[Object.Az];
  472.     coszangle=cosine[Object.Az];
  473.  
  474.     for(i=0;i<Object.NumOfVertices;i++)
  475.     {
  476.         vert=&Object.Vertex[i];
  477.  
  478.         // rotate around the x-axis
  479.         vert->Nwz=FixedMul(vert->Noy , cosxangle) - FixedMul(vert->Noz , sinxangle);
  480.         vert->Nwy=FixedMul(vert->Noy , sinxangle) + FixedMul(vert->Noz , cosxangle);
  481.         vert->Nwx=vert->Nox;
  482.  
  483.         // rotate around the y-axis
  484.         nx=FixedMul(vert->Nwx , cosyangle) - FixedMul(vert->Nwz , sinyangle);
  485.         nz=FixedMul(vert->Nwx , sinyangle) + FixedMul(vert->Nwz , cosyangle);
  486.         vert->Nwx=nx;
  487.         vert->Nwz=nz;
  488.  
  489.         // rotate around the z-axis
  490.         nx=FixedMul(vert->Nwx , coszangle) - FixedMul(vert->Nwy , sinzangle);
  491.         ny=FixedMul(vert->Nwx , sinzangle) + FixedMul(vert->Nwy , coszangle);
  492.  
  493.         // reverse the direction of the normals for lightsource shading
  494.         vert->Nwx=-nx;
  495.         vert->Nwy=-ny;
  496.         vert->Nwz=-nz;
  497.     }
  498. }
  499.  
  500.  
  501. //───────────────────── set up light source coordinates ──────────────────
  502.  
  503.  
  504. void SetupLightSource(void)
  505. {
  506.     double xlen,ylen,zlen,length;
  507.  
  508.     // assign the delault light source position
  509.     xlen=0;
  510.     ylen=0;
  511.     zlen=10;
  512.  
  513.     // calculate the length of the vector (light source to 0,0,0)
  514.     length = sqrt(xlen*xlen + ylen*ylen + zlen*zlen);
  515.  
  516.     // scale it to a unit vector
  517.     LightSource.x = Float2Fixed(xlen/length);
  518.     LightSource.y = Float2Fixed(ylen/length);
  519.     LightSource.z = Float2Fixed(zlen/length);
  520. }
  521.  
  522.  
  523.  
  524. //────────────────────── rotate light source ─────────────────────────────
  525.  
  526.  
  527. void RotateLightSource(void)
  528. {
  529.     int i;
  530.     Fixedpoint nx,ny,nz;
  531.     Fixedpoint cosxangle,sinxangle,cosyangle,sinyangle,coszangle,sinzangle;
  532.  
  533.     // update the light source rotation angles
  534.     LightSource.ax+=8; if(LightSource.ax>=MAXDEGREES) LightSource.ax=0;
  535.     LightSource.ay+=8; if(LightSource.ay>=MAXDEGREES) LightSource.ay=0;
  536.     LightSource.az+=8; if(LightSource.az>=MAXDEGREES) LightSource.az=0;
  537.  
  538.     // get sine and cosine angles to save time from table lookup in inner loop
  539.     sinxangle=sine[LightSource.ax];
  540.     cosxangle=cosine[LightSource.ax];
  541.     sinyangle=sine[LightSource.ay];
  542.     cosyangle=cosine[LightSource.ay];
  543.     sinzangle=sine[LightSource.az];
  544.     coszangle=cosine[LightSource.az];
  545.  
  546.     // rotate around the x-axis
  547.     LightSource.wz=FixedMul(LightSource.y , cosxangle) - FixedMul(LightSource.z , sinxangle);
  548.     LightSource.wy=FixedMul(LightSource.y , sinxangle) + FixedMul(LightSource.z , cosxangle);
  549.     LightSource.wx=LightSource.x;
  550.  
  551.     // rotate around the y-axis
  552.     nx=FixedMul(LightSource.wx, cosyangle) - FixedMul(LightSource.wz , sinyangle);
  553.     nz=FixedMul(LightSource.wx, sinyangle) + FixedMul(LightSource.wz , cosyangle);
  554.     LightSource.wx=nx;
  555.     LightSource.wz=nz;
  556.  
  557.     // rotate around the z-axis
  558.     nx=FixedMul(LightSource.wx , coszangle) - FixedMul(LightSource.wy , sinzangle);
  559.     ny=FixedMul(LightSource.wx , sinzangle) + FixedMul(LightSource.wy , coszangle);
  560.  
  561.     // reverse the direction of the normals for lightsource shading
  562.     LightSource.wx=-nx;
  563.     LightSource.wy=-ny;
  564.     LightSource.wz=-nz;
  565. }
  566.  
  567.  
  568.  
  569. //─────────────────────────── MAIN PROGRAM ───────────────────────────────
  570.  
  571.  
  572. int main(void)
  573. {
  574.     int y;
  575.     char keypress;
  576.  
  577.     clrscr();
  578.     printf("GOURAUD VECTORS\n by Tumblin / Bodies In Motion '95\n");
  579.  
  580.     LoadObject();
  581.  
  582.     printf("\n\nPress any key to begin, and again to end.\n\n");
  583.     getch();
  584.  
  585.     CreateLookupTables();
  586.  
  587.     SetupLightSource();
  588.     CalculateNormals();
  589.  
  590.     x_text_init();
  591.  
  592.     x_set_mode(X_MODE_320x240,320);
  593.     x_set_doublebuffer(240);
  594.     x_set_cliprect(0,0,79,239);
  595.     x_put_pal_raw(palette,256,0); // setup VED 1.0 palette colors
  596.  
  597.     // initialize the position and angles of object
  598.     Object.Ox=Int2Fixed(0);
  599.     Object.Oy=Int2Fixed(0);
  600.     Object.Oz=Int2Fixed(-1024);
  601.     Object.Ax=0;
  602.     Object.Ay=0;
  603.     Object.Az=0;
  604.  
  605.     // run the demo until user hits key
  606.     do
  607.     {
  608.         Object.Ax+=8; if(Object.Ax >=MAXDEGREES) Object.Ax=0;
  609.         Object.Ay-=8; if(Object.Ay <0) Object.Ay=MAXDEGREES-1;
  610.         Object.Az+=6; if(Object.Az >=MAXDEGREES) Object.Az=0;
  611.         RotateObject();
  612.         RotateNormals();
  613.         RotateLightSource();
  614.         CalculateColor();
  615.         MakePolygonList();
  616.         SortPolygons();
  617.         DrawPolygons();
  618.         x_page_flip(0,0);
  619.     }while(!kbhit());
  620.     getch();
  621.  
  622.     x_text_mode();
  623.     printf("GOURAUD VECTORS\n");
  624.     printf("coded by Tumblin / Bodies In Motion '95\n");
  625.     printf("(aka Terry Sznober)\n");
  626.     printf("You can email me at tumblin@mi.net\n");
  627.     printf("Greetings to everyone in the demo scene!\n");
  628.     printf("Special greets to all the cool people I met at NAID '95!\n");
  629.     return(0);
  630. }
  631.  
  632.  
  633. //--------------------- Gouraud Shaded Triangle routine ------------------
  634.  
  635.  
  636. void GTriangle(float x1,float y1,float c1,
  637.                              float x2,float y2,float c2,
  638.                              float x3,float y3,float c3,
  639.                              int pageoffs)
  640. {
  641.     float mx; // slope dy/dx
  642.     float mc; // slope dc/dx
  643.     float x; // x screen coordinate
  644.     float c; // color of pixel to plot
  645.     int count; // looping variable
  646.     int y; // looping variable
  647.     float cl; // color of left edge of horizontal scanline
  648.     float cr; // color of right edge of horizontal scanline
  649.     float el; // coordinate of left edge of horizontal scanline
  650.     float er; // coordinate of right edge of horizontal scanline
  651.  
  652.  
  653.     // initialize the edge buffers to extreme values
  654.     for(count=0;count<240;count++)
  655.     {
  656.         edge_l[count]=319;
  657.         edge_r[count]=0;
  658.     }
  659.  
  660.     // scan the edges of the triangle
  661.     ScanEdge(x1,y1,c1, x2,y2,c2);
  662.     ScanEdge(x2,y2,c2, x3,y3,c3);
  663.     ScanEdge(x3,y3,c3, x1,y1,c1);
  664.  
  665.     // gouraud fill the horizontal scanlines
  666.     for(y=0;y<240;y++)
  667.     {
  668.         // if the scanline is valid (ie left coordinate < right coordinate)
  669.         if(edge_l[y] <= edge_r[y])
  670.         {
  671.             cl=(float)color_l[y];
  672.             cr=(float)color_r[y];
  673.             el=(float)edge_l[y];
  674.             er=(float)edge_r[y];
  675.  
  676.             // now calculate slope of color (dc/dx)
  677.  
  678.             if( (er-el) == 0)
  679.             {
  680.                 // denominator will be zero so don't do the division so use dc
  681.                 mc = (cr-cl);
  682.             }
  683.             else
  684.             {
  685.                 // denominator okay, so use dc/dx
  686.                 mc = (cr-cl)/(er-el);
  687.             }
  688.             c = cl; // start with color of left edge of scanline
  689.             // loop through every pixel in horizontal scanline
  690.             for(count=(int)edge_l[y]; count < (int)edge_r[y]; count++)
  691.             {
  692.                 x_put_pix(count,y,pageoffs,(int)c);
  693.                 c+=mc; // increase the color by dc/dx
  694.             }
  695.         }
  696.     }
  697. }
  698.  
  699.  
  700. void ScanEdge(float x1,float y1,float c1,float x2,float y2,float c2)
  701. {
  702.     // scan-convert (x1,y1,c1)-(x2,y2,c2)
  703.  
  704.     float mx; // slope dx/dy
  705.     float mc; // slope dc/dy
  706.     float x; // x pixel coordinate
  707.     float c; // pixel's color
  708.     int count; // looping variable
  709.     float temp; // used for swapping
  710.  
  711.     // make sure that edge goes from top to bottom
  712.     if( (y2-y1) < 0 )
  713.     {
  714.         // swap y2 with y1
  715.         temp=y1;
  716.         y1=y2;
  717.         y2=temp;
  718.         // swap x2 with x1
  719.         temp=x1;
  720.         x1=x2;
  721.         x2=temp;
  722.         // swap c2 with c1
  723.         temp=c1;
  724.         c1=c2;
  725.         c2=temp;
  726.     }
  727.  
  728.     // initialize for stepping
  729.     if( (y2-y1) != 0)
  730.     {
  731.         mx = (x2-x1)/(y2-y1); // dx/dy
  732.         mc = (c2-c1)/(y2-y1); // dc/dy
  733.     }
  734.     else
  735.     {
  736.         mx = (x2-x1); // dx
  737.         mc = (c2-c1); // dc
  738.     }
  739.     x = x1; // starting x coordinate
  740.     c = c1; // starting c color
  741.  
  742.     // step through edge and record color values along the way
  743.     for(count=y1; count < y2; count++)
  744.     {
  745.         if(x < (float)edge_l[count])
  746.         {
  747.             edge_l[count]=(int)x;
  748.             color_l[count]=(int)c;
  749.         }
  750.         if(x > (float)edge_r[count])
  751.         {
  752.             edge_r[count]=(int)x;
  753.             color_r[count]=(int)c;
  754.         }
  755.         x+=mx;  // x = x + dx/dy
  756.         c+=mc;  // c = c + dc/dy
  757.     }
  758. }
  759.